package snapex.core.controller;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import org.springframework.http.ResponseEntity;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import lombok.extern.slf4j.Slf4j;
import snapex.core.OperationNotAllowException;
import snapex.core.SnapexApplicationException;
import snapex.core.Status;
import snapex.core.ValidationFailureException;
import snapex.core.model.Result;

@Slf4j
@ControllerAdvice
public class ExceptionHandlerAdvice {
	    
	@ExceptionHandler(ValidationFailureException.class)
	@ResponseBody
	public ResponseEntity<Result> handleValidationFailureException(ValidationFailureException e) {
		
    	Result result = Result.failure(Status.ValidationError);

		Map<String,String> fieldErrors = new HashMap<String,String>();
		for(FieldError field : e.getBindingResult().getFieldErrors()) {
			fieldErrors.put(field.getField(),field.getDefaultMessage());
		}
		
		Map<String,String> globalErrors = new HashMap<String,String>();
		for(ObjectError obj : e.getBindingResult().getGlobalErrors()) {
			globalErrors.put(obj.getCode(),obj.getDefaultMessage());
		}
		
		if(!fieldErrors.isEmpty()) {
			result.fieldErrors(fieldErrors);
		}
		if(!globalErrors.isEmpty()) {
			result.globalErrors(globalErrors);
		}
		
		return ResponseEntity.ok(result);
	}
    
	@ExceptionHandler(OperationNotAllowException.class)
	@ResponseBody
	public ResponseEntity<Result> handleOperationNotAllowException(OperationNotAllowException e) {
		
		return ResponseEntity.ok(Result.failure(Status.OperationNotAllow));
	}
	
	@ExceptionHandler(SnapexApplicationException.class)
	@ResponseBody
	public ResponseEntity<Result> handleSnapexApplicationException(SnapexApplicationException e) {
		
		return ResponseEntity.ok(Result.failure().msg(e.getMessage()));
	}
	
	@ExceptionHandler(SQLException.class)
	@ResponseBody
	public ResponseEntity<Result> handleSQLException(SQLException e) {
		log.error("***SQLException***",e);
		return ResponseEntity.ok(Result.failure().msg("Internal SQL error: Failed to perform operation"));
	}
	
	@ExceptionHandler(Exception.class)
	@ResponseBody
	public ResponseEntity<Result> handleException(Exception e) {
		log.error("***Exception***",e);
		return ResponseEntity.ok(Result.failure().msg("Internal server error: Failed to perform operation"));
	}
}
